// tspcluster - Traveling Salesman Problem
// Copyright (C) 2006  Frederik Carlier
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Collections.ObjectModel;

namespace UGent.Tsp
{
    public static class Swappers
    {
        public static Type GetOptimalSwapper()
        {
            return typeof(Swap311);
        }

        public static int GetCountForOptimalSwapper()
        {
            return 0;
        }

        public static ReadOnlyCollection<Type> ListSwappers()
        {
            Type[] types = typeof(Swappers).Assembly.GetTypes();
            List<Type> swappers = new List<Type>();

            foreach (Type type in types)
            {
                if (!type.IsAbstract && type.GetInterface(typeof(ISwapper).Name) != null)
                {
                    swappers.Add(type);
                }
            }

            swappers.Sort(new TypeComparer());

            return new ReadOnlyCollection<Type>(swappers);
        }

        public static bool HasParameter(Type type)
        {
            HasParameterAttribute[] hasParameter = (HasParameterAttribute[])type.GetCustomAttributes(typeof(HasParameterAttribute), false);

            if (hasParameter.Length == 0)
                return false;
            return hasParameter[0].Value;
        }

        public static ReadOnlyCollection<int> GetOptimalValues(Type type)
        {
            if(!HasParameter(type))
                throw new InvalidOperationException();

            HasParameterAttribute[] hasParameter = (HasParameterAttribute[])type.GetCustomAttributes(typeof(HasParameterAttribute), false);

            return hasParameter[0].OptimalValues;
        }

        public static ISwapper Create(Type type)
        {
            return Create(type, new object[] { });
        }

        public static ISwapper Create(Type type, int count)
        {
            return Create(type, new object[] { count });
        }

        public static ISwapper Create(Type type, Map map)
        {
            return Create(type, new object[] { map });
        }

        public static ISwapper Create(Type type, Map map, int count)
        {
            Route route = new Route(map);
            return Create(type, new object[] { route, count });
        }

        public static ISwapper Create(Type type, Route route, int count)
        {
            return Create(type, new object[] { route, count });
        }

        private static ISwapper Create(Type type, object[] args)
        {
            if (type == null)
                throw new ArgumentNullException("type");

            if (type.GetInterface(typeof(ISwapper).Name, false) == null)
                throw new ArgumentOutOfRangeException("type");

            return (ISwapper)Activator.CreateInstance(type, args);
        }
    }
}
